#!/usr/bin/python
import xml.dom.minidom
import types
import getopt, sys
import xml.parsers.expat

def parsefile(conf_file):
    """
    Used to a configuration in xml format
    """
    parser = xml.parsers.expat.ParserCreate()
    parser.ParseFile(open(conf_file, "r"))

def toHex(input_str):
    """
    convert input string to a hex string
    """
    lst = []
    i = 0
    if(type(input_str) is types.StringType):
        for ch in input_str:
            hex_ch = hex(ord(ch)).replace('0x', '')
            if len(hex_ch) == 1:
                hex_ch = '0' + hex_ch
            lst.append(hex_ch)
            if i != len(input_str) - 1:
    	        lst.append(":")
            i = i + 1
    if(type(input_str) is types.IntType):
        hex_int = hex(input_str).replace('0x', '')
        if len(hex_int) == 1 or len(hex_int)%2 != 0:
            hex_int = '0' + hex_int
        for i in range(0, len(hex_int), 2):
            lst.append(hex_int[i: i+2])
            if i+2 != len(hex_int):
                lst.append(":")
            
    return reduce(lambda x, y:x+y, lst)

def toHexLen2(in_str):
    """
    convert int to hex, make sure the output is 2-byte format
    """
    lst = []
    i = 0
    if(type(in_str) is types.IntType):
        hex_int = hex(in_str).replace('0x', '')
        if len(hex_int) == 1 or len(hex_int)%2 != 0:
            hex_int = '0' + hex_int
        if len(hex_int) == 2:
            hex_int = '00' + hex_int
        for i in range(0, len(hex_int), 2):
            lst.append(hex_int[i: i+2])
            if i+2 != len(hex_int):
                lst.append(":")
            
    return reduce(lambda x, y:x+y, lst)


def getText(nodelist):
    rc = []
    for node in nodelist:
        if node.nodeType == node.TEXT_NODE:
            rc.append(node.data)
    return ''.join(rc)

def handleNDNConfig(ndn_config, dst):
    """
    parse NDN configurations
    """
    nac_config = ndn_config.getElementsByTagName("nacserver")[0]
    FILE = open(dst, "w")
    line = """
#####################################################
#Add this at the end of your dhcpd.conf
#####################################################
option NAC_SERVER code 246 = string;
option NDN_GATEWAYS code 247 = string;
option NDN_NAMESPACE code 248 = text;
local-port 6867;
remote-port 6868;
\n
"""
    FILE.write(line)
    line = "subnet xxx.xxx.xxx.xxx netmask xxx.xxx.xxx.xxx {\n\tauthoritative;\n"
    FILE.write(line)
    line = "\toption NAC_SERVER "+ handleNacServerConfig(nac_config)+";\n"
    FILE.write(line)
    line = "\toption NDN_GATEWAYS " + handleGWConfig(ndn_config.getElementsByTagName("gateway")[0])+";\n"
    FILE.write(line)
    line = "\toption NDN_NAMESPACE \"" + getText(ndn_config.getElementsByTagName("namespace")[0].childNodes).strip()+"\";\n}\n" 
    FILE.write(line)
    FILE.close()

def handleNacServerConfig(host_config):
    """
    parse a NAC server
    """
    tmp_str = []
    tmp_str.append(handleHosts(host_config.getElementsByTagName("host")))
    if len(tmp_str) == 0:
        return ""
    return reduce(lambda x, y:x+y, tmp_str)

def handleGWConfig(gw_config):
    """
    parse a NDN gateway
    """
    tmp_str = []
    tmp_str.append(handleGWHosts(gw_config.getElementsByTagName("host")))
    if len(tmp_str) == 0:
        return ""
    return reduce(lambda x, y:x+y, tmp_str)

def handleGWHosts(hosts):
    tmp_str = []
    tmp_str.append(toHex(len(hosts)))
    tmp_str.append(":")
    i = 0
    for host in hosts:
        tmp = handleGWHost(host)
        tmp_str.append(tmp)
        if i != len(hosts) - 1:
            tmp_str.append(":")
        i += 1
    if len(tmp_str) == 0:
        return ""
    return reduce(lambda x, y:x+y, tmp_str)

def handleHosts(hosts):
    tmp_str = []
    tmp_str.append(toHex(len(hosts)))
    tmp_str.append(":")
    i = 0
    for host in hosts:
        tmp = handleHost(host)
        tmp_str.append(tmp)
        if i != len(hosts) - 1:
            tmp_str.append(":")
        i += 1
    if len(tmp_str) == 0:
        return ""
    return reduce(lambda x, y:x+y, tmp_str)

def handleGWHost(host):
    tmp_str = []
    tmp_str.append(handleHostAfi(host.getElementsByTagName("protocol")[0]))
    tmp_str.append(":")
    tmp_str.append(handleHostAfi(host.getElementsByTagName("afi")[0]))
    tmp_str.append(":")
    tmp_str.append(handleHostAddr(host.getElementsByTagName("addr")[0]))
    tmp_str.append(":")
    tmp_str.append(handleHostPort(host.getElementsByTagName("port")[0]))
    tmp_str.append(":")
    tmp_str.append(handleGWPrefixes(host.getElementsByTagName("prefixes")[0]))
    if len(tmp_str) == 0:
        return ""
    return reduce(lambda x, y:x+y, tmp_str)

def handleGWPrefixes(gw_prefixes):
    tmp_str = []
    tmp_str.append(handleHostPrefixes(gw_prefixes.getElementsByTagName("nameprefix")))

    if len(tmp_str) == 0:
        return ""
    return reduce(lambda x, y:x+y, tmp_str)

def handleHostPrefixes(prefixes):
    tmp_str = []
    i = 0

    tmp_str.append(handlePrefixNumber(len(prefixes)))
    tmp_str.append(":")
    for prefix in prefixes:
        tmp = handlePrefix(prefix)
        tmp_str.append(tmp)
        if i != len(prefixes) - 1:
            tmp_str.append(":")
        i += 1
    if len(tmp_str) == 0:
        return ""
    return reduce(lambda x, y:x+y, tmp_str)

def handlePrefix(prefix):
    res = []
    tmp_str = getText(prefix.childNodes).encode('unicode_escape')
    prefixlen = len(tmp_str)
    res.append(toHexLen2(prefixlen))
    res.append(":")
    res.append(toHex(tmp_str))
    if len(res) == 0:
        return ""
    return reduce(lambda x, y:x+y, res)

def handleHost(host):
    tmp_str = []
    tmp_str.append(handleHostAfi(host.getElementsByTagName("afi")[0]))
    tmp_str.append(":")
    tmp_str.append(handleHostAddr(host.getElementsByTagName("addr")[0]))
    if len(tmp_str) == 0:
        return ""
    return reduce(lambda x, y:x+y, tmp_str)

def handleHostAfi(afi):
    """
    afi is the address type, 0=v4, 1=v6
    """
    tmp_str = int(getText(afi.childNodes))
    return toHex(tmp_str)

def handleHostPort(port):
    """
    get a host's port, make sure it is 2-byte
    """
    tmp_str = int(getText(port.childNodes))
    return toHexLen2(tmp_str)

def handlePrefixNumber(number):
    """
    get the prefix number, and this number must be 2-byte
    """
    return toHexLen2(number)

def handleHostAddr(addr):
    """
    parse an host's address
    """
    ip = getText(addr.childNodes).encode('unicode_escape').split(".")
    tmp_str = []
    i = 0
    for element in ip:
        tmp_str.append(toHex(int(element)))
        if i != len(ip) - 1:
            tmp_str.append(":")
        i += 1 
    if len(tmp_str) == 0:
        return ""
    return reduce(lambda x, y:x+y, tmp_str)

def usage():
    """
    How to use this app
    """
    print "usage: ", sys.argv[0], "<-f config file> <-d result file>"
    sys.exit(2)

if __name__ == '__main__':
    try:
        opts, args = getopt.getopt(sys.argv[1:], "f:d:")
    except getopt.GetoptError:
        sys.stdout = sys.stderr
        usage()
    src_file = ""
    dst_file = ""
    opt_num = 0
    for o, a in opts:
        if o == "-f":
            src_file = a
            opt_num = opt_num + 1
        if o == "-d":
            dst_file = a
            opt_num = opt_num + 1
    if opt_num != 2:
        usage()

    #validating the file
    try:
        parsefile(src_file)
    except Exception, e:
        print "%s is %s" % (src_file, e)
        sys.exit(2)

    conf_file = open(src_file, 'r')
    document = conf_file.read()
    conf_file.close()
    
    res_dom = xml.dom.minidom.parseString(document)

    handleNDNConfig(res_dom, dst_file)
